home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-11-19 | 79.0 KB | 2,413 lines |
- //==========================================================================;
- //
- // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
- // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
- // PURPOSE.
- //
- // Copyright (c) 1992, 1993 Microsoft Corporation. All Rights Reserved.
- //
- //--------------------------------------------------------------------------;
- //
- // codec.c
- //
- // Description:
- //
- //
- //
- //==========================================================================;
-
- #include <windows.h>
- #include <windowsx.h>
- #include <mmsystem.h>
- #include <mmreg.h>
- #include <msacm.h>
- #include <msacmdrv.h>
- #include <memory.h>
-
- #include "codec.h"
- #include "msfilter.h"
-
- #include "debug.h"
-
-
- //
- // array of WAVE format tags supported.
- //
- // NOTE! if you change anything in this structure (order, addition, removal)
- // you must also fix acmdFormatTagDetails!
- //
- static UINT gauFormatTagIndexToTag[] =
- {
- WAVE_FORMAT_PCM
- };
-
- #define ACM_DRIVER_MAX_FORMAT_TAGS SIZEOF_ARRAY(gauFormatTagIndexToTag)
-
-
- //
- // array of _standard_ sample rates supported
- //
- //
- static UINT gauFormatIndexToSampleRate[] =
- {
- 8000,
- 11025,
- 22050,
- 44100
- };
-
- #define ACM_DRIVER_MAX_SAMPLE_RATES SIZEOF_ARRAY(gauFormatIndexToSampleRate)
-
- //
- //
- //
- //
- #define ACM_DRIVER_MAX_CHANNELS (MSFILTER_MAX_CHANNELS)
-
-
- //
- // array of bits per sample supported
- //
- //
- static UINT gauFormatIndexToBitsPerSample[] =
- {
- 8,
- 16
- };
-
- #define ACM_DRIVER_MAX_BITSPERSAMPLE_PCM SIZEOF_ARRAY(gauFormatIndexToBitsPerSample)
-
-
- //
- // number of formats we enumerate per channel is number of sample rates
- // times number of channels times number of types (bits per sample).
- //
- #define ACM_DRIVER_MAX_STANDARD_FORMATS_PCM (ACM_DRIVER_MAX_SAMPLE_RATES * \
- ACM_DRIVER_MAX_CHANNELS * \
- ACM_DRIVER_MAX_BITSPERSAMPLE_PCM)
-
-
- //
- // Array of WAVE filter tags supported.
- //
- static DWORD gadwFilterTagIndexToTag[] =
- {
- WAVE_FILTER_VOLUME,
- WAVE_FILTER_ECHO
- };
-
- #define ACM_DRIVER_MAX_FILTER_TAGS SIZEOF_ARRAY(gadwFilterTagIndexToTag)
-
-
- //
- // Array of filters supported.
- //
- static DWORD gdwFilterIndexToVolume[] =
- {
- 0x00001000,
- 0x00002000,
- 0x00004000,
- 0x00006000,
- 0x00008000,
- 0x0000A000,
- 0x0000C000,
- 0x0000E000,
- 0x0000F000,
- 0x00011000,
- 0x00012000,
- 0x00014000,
- 0x00016000,
- 0x00018000,
- 0x0001A000,
- 0x0001C000,
- 0x00020000
- };
- #define ACM_DRIVER_MAX_VOLUME_FILTERS SIZEOF_ARRAY(gdwFilterIndexToVolume)
-
- static DWORD gdwFilterIndexToDelay[] =
- {
- 0x00000040,
- 0x00000080,
- 0x00000100,
- 0x00000180,
- 0x00000200,
- 0x00000300,
- 0x00000400,
- 0x00000800,
- };
- #define ACM_DRIVER_NUM_DELAY SIZEOF_ARRAY(gdwFilterIndexToDelay)
-
- static DWORD gdwFilterIndexToEchoVol[] =
- {
- 0x00001000,
- 0x00002000,
- 0x00004000,
- 0x00008000,
- 0x0000C000
- };
- #define ACM_DRIVER_NUM_ECHOVOL SIZEOF_ARRAY(gdwFilterIndexToEchoVol)
-
- #define ACM_DRIVER_MAX_ECHO_FILTERS (ACM_DRIVER_NUM_DELAY * \
- ACM_DRIVER_NUM_ECHOVOL)
-
-
- //
- //
- //
- //
- TCHAR BCODE gszIniSystem[] = TEXT("system.ini");
- TCHAR BCODE gszKeyConfig[] = TEXT("Config");
-
-
- //==========================================================================;
- //
- //
- //
- //
- //==========================================================================;
-
- //--------------------------------------------------------------------------;
- //
- // BOOL pcmIsValidFormat
- //
- // Description:
- // This function verifies that a wave format header is a valid PCM
- // header that _this_ ACM driver can deal with.
- //
- // Arguments:
- // LPWAVEFORMATEX pwfx: Pointer to format header to verify.
- //
- // Return (BOOL):
- // The return value is non-zero if the format header looks valid. A
- // zero return means the header is not valid.
- //
- //--------------------------------------------------------------------------;
-
- BOOL FNLOCAL pcmIsValidFormat
- (
- LPWAVEFORMATEX pwfx
- )
- {
- if (NULL == pwfx)
- return (FALSE);
-
- if (WAVE_FORMAT_PCM != pwfx->wFormatTag)
- return (FALSE);
-
- //
- // verify nChannels member is within the allowed range
- //
- if ((pwfx->nChannels < 1) || (pwfx->nChannels > ACM_DRIVER_MAX_CHANNELS))
- return (FALSE);
-
- //
- // only allow the bits per sample that we can encode and decode with
- //
- if ((8 != pwfx->wBitsPerSample) && (16 != pwfx->wBitsPerSample))
- return (FALSE);
-
- //
- // now verify that the block alignment is correct..
- //
- if (PCM_BLOCKALIGNMENT(pwfx) != pwfx->nBlockAlign)
- return (FALSE);
-
- //
- // verify samples per second is within our capabilities
- //
- if ((0L == pwfx->nSamplesPerSec) || (0x3FFFFFFF < pwfx->nSamplesPerSec))
- {
- return (FALSE);
- }
-
- //
- // finally, verify that avg bytes per second is correct
- //
- if (PCM_AVGBYTESPERSEC(pwfx) != pwfx->nAvgBytesPerSec)
- return (FALSE);
-
- return (TRUE);
- } // pcmIsValidFormat()
-
-
- //--------------------------------------------------------------------------;
- //
- // BOOL volumeIsValidFilter
- //
- // Description:
- // This function verifies that a wave filter header is a valid volume
- // header that our volume converter can deal with.
- //
- // Arguments:
- // LPWAVEFILTER pwf: Pointer to filter header to verify.
- //
- // Return (BOOL):
- // The return value is non-zero if the format header looks valid. A
- // zero return means the header is not valid.
- //
- // History:
- // 06/05/93 Created.
- //
- //--------------------------------------------------------------------------;
-
- BOOL FNLOCAL volumeIsValidFilter
- (
- LPWAVEFILTER pwf
- )
- {
- if (!pwf)
- return (FALSE);
-
- if (pwf->cbStruct < sizeof(VOLUMEWAVEFILTER))
- return (FALSE);
-
- if (pwf->dwFilterTag != WAVE_FILTER_VOLUME)
- return (FALSE);
-
- if (0L != pwf->fdwFilter)
- return (FALSE);
-
- return (TRUE);
- } // volumeIsValidFilter()
-
-
-
- //--------------------------------------------------------------------------;
- //
- // BOOL echoIsValidFilter
- //
- // Description:
- // This function verifies that a wave filter header is a valid echo
- // header that our echo converter can deal with.
- //
- // Arguments:
- // LPWAVEFILTER pwf: Pointer to filter header to verify.
- //
- // Return (BOOL):
- // The return value is non-zero if the format header looks valid. A
- // zero return means the header is not valid.
- //
- // History:
- // 06/05/93 Created.
- //
- //--------------------------------------------------------------------------;
-
- BOOL FNLOCAL echoIsValidFilter
- (
- LPWAVEFILTER pwf
- )
- {
- LPECHOWAVEFILTER pwfEcho;
-
- if (!pwf)
- return (FALSE);
-
- if (pwf->cbStruct < sizeof(ECHOWAVEFILTER))
- return (FALSE);
-
- if (pwf->dwFilterTag != WAVE_FILTER_ECHO)
- return (FALSE);
-
- if (0L != pwf->fdwFilter)
- return (FALSE);
-
- pwfEcho = (LPECHOWAVEFILTER)pwf;
- // We only support a delay value up to 10 sec or 10 000 msec.
- if (pwfEcho->dwDelay > 10000L)
- return (FALSE);
-
- return (TRUE);
- } // echoIsValidFilter()
-
-
- //==========================================================================;
- //
- //
- //
- //
- //==========================================================================;
-
-
- //--------------------------------------------------------------------------;
- //
- // LRESULT acmdDriverOpen
- //
- // Description:
- // This function is used to handle the DRV_OPEN message for the ACM
- // driver. The driver is 'opened' for many reasons with the most common
- // being in preperation for conversion work. It is very important that
- // the driver be able to correctly handle multiple open driver
- // instances.
- //
- // Read the comments for this function carefully!
- //
- // Note that multiple _streams_ can (and will) be opened on a single
- // open _driver instance_. Do not store/create instance data that must
- // be unique for each stream in this function. See the acmdStreamOpen
- // function for information on conversion streams.
- //
- // Arguments:
- // HDRVR hdrvr: Driver handle that will be returned to caller of the
- // OpenDriver function. Normally, this will be the ACM--but this is
- // not guaranteed. For example, if an ACM driver is implemented within
- // a waveform driver, then the driver will be opened by both MMSYSTEM
- // and the ACM.
- //
- // LPACMDRVOPENDESC paod: Open description defining how the ACM driver
- // is being opened. This argument may be NULL--see the comments below
- // for more information.
- //
- // Return (LRESULT):
- // The return value is non-zero if the open is successful. A zero
- // return signifies that the driver cannot be opened.
- //
- //--------------------------------------------------------------------------;
-
- LRESULT FNLOCAL acmdDriverOpen
- (
- HDRVR hdrvr,
- LPACMDRVOPENDESC paod
- )
- {
- PDRIVERINSTANCE pdi;
-
- //
- // the [optional] open description that is passed to this driver can
- // be from multiple 'managers.' for example, AVI looks for installable
- // drivers that are tagged with 'vidc' and 'vcap'. we need to verify
- // that we are being opened as an Audio Compression Manager driver.
- //
- // if paod is NULL, then the driver is being opened for some purpose
- // other than converting (that is, there will be no stream open
- // requests for this instance of being opened). the most common case
- // of this is the Control Panel's Drivers option checking for config
- // support (DRV_[QUERY]CONFIGURE).
- //
- // we want to succeed this open, but be able to know that this
- // open instance is bogus for creating streams. for this purpose we
- // leave most of the members of our instance structure that we
- // allocate below as zero...
- //
- if (NULL != paod)
- {
- //
- // refuse to open if we are not being opened as an ACM driver.
- // note that we do NOT modify the value of paod->dwError in this
- // case.
- //
- if (ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC != paod->fccType)
- {
- return (0L);
- }
- }
-
-
- //
- // we are being opened as an installable driver--we can allocate some
- // instance data to be returned in dwId argument of the DriverProc;
- // or simply return non-zero to succeed the open.
- //
- // this driver allocates a small instance structure. note that we
- // rely on allocating the memory as zero-initialized!
- //
- pdi = (PDRIVERINSTANCE)LocalAlloc(LPTR, sizeof(*pdi));
- if (NULL == pdi)
- {
- //
- // if this open attempt was as an ACM driver, then return the
- // reason we are failing in the open description structure..
- //
- if (NULL != paod)
- {
- paod->dwError = MMSYSERR_NOMEM;
- }
-
- //
- // fail to open
- //
- return (0L);
- }
-
-
- //
- // fill in our instance structure... note that this instance data
- // can be anything that the ACM driver wishes to maintain the
- // open driver instance. this data should not contain any information
- // that must be maintained per open stream since multiple streams
- // can be opened on a single driver instance.
- //
- // also note that we do _not_ check the version of the ACM opening
- // us (paod->dwVersion) to see if it is at least new enough to work
- // with this driver (for example, if this driver required Version 3.0
- // of the ACM and a Version 2.0 installation tried to open us). the
- // reason we do not fail is to allow the ACM to get the driver details
- // which contains the version of the ACM that is _required_ by this
- // driver. the ACM will examine that value (in padd->vdwACM) and
- // do the right thing for this driver... like not load it and inform
- // the user of the problem.
- //
- pdi->hdrvr = hdrvr;
-
-
- if (NULL != paod)
- {
- pdi->fnDriverProc = NULL;
- pdi->fccType = paod->fccType;
- pdi->vdwACM = paod->dwVersion;
- pdi->fdwOpen = paod->dwFlags;
-
- #if 0
- pdi->fdwConfig = GetPrivateProfileInt(paod->pszAliasName,
- gszKeyConfig,
- MSFILTER_CONFIG_DEFAULT,
- gszIniSystem);
- #endif
-
- paod->dwError = MMSYSERR_NOERROR;
- }
-
-
- //
- // non-zero return is success for DRV_OPEN
- //
- return ((LRESULT)(UINT)pdi);
- } // acmdDriverOpen()
-
-
- //--------------------------------------------------------------------------;
- //
- // LRESULT acmdDriverClose
- //
- // Description:
- // This function handles the DRV_CLOSE message for the ACM driver. The
- // driver receives a DRV_CLOSE message for each succeeded DRV_OPEN
- // message (see acmdDriverOpen). The driver will only receive a close
- // message for _successful_ opens.
- //
- // Arguments:
- // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
- // This structure is [optionally] allocated during the DRV_OPEN message
- // which is handled by the acmdDriverOpen function.
- //
- // Return (LRESULT):
- // The return value is non-zero if the open instance can be closed.
- // A zero return signifies that the ACM driver instance could not be
- // closed.
- //
- // NOTE! It is _strongly_ recommended that the driver never fail to
- // close. Note that the ACM will never allow a driver instance to
- // be closed if there are open streams. An ACM driver does not need
- // to check for this case.
- //
- //--------------------------------------------------------------------------;
-
- LRESULT FNLOCAL acmdDriverClose
- (
- PDRIVERINSTANCE pdi
- )
- {
- //
- // check to see if we allocated instance data. if we did not, then
- // immediately succeed.
- //
- if (NULL != pdi)
- {
- //
- // close down the driver instance. this driver simply needs
- // to free the instance data structure... note that if this
- // 'free' fails, then this ACM driver probably trashed its
- // heap; assume we didn't do that.
- //
- LocalFree((HLOCAL)pdi);
- }
-
-
- //
- // non-zero return is success for DRV_CLOSE
- //
- return (1L);
- } // acmdDriverClose()
-
-
- //--------------------------------------------------------------------------;
- //
- // LRESULT acmdDriverConfigure
- //
- // Description:
- // This function is called to handle the DRV_[QUERY]CONFIGURE messages.
- // These messages are for 'configuration' support of the driver.
- // Normally this will be for 'hardware'--that is, a dialog should be
- // displayed to configure ports, IRQ's, memory mappings, etc if it
- // needs to. However, a software only ACM driver may also require
- // configuration for 'what is real time' or other quality vs time
- // issues.
- //
- // The most common way that these messages are generated under Win 3.1
- // and NT Product 1 is from the Control Panel's Drivers option. Other
- // sources may generate these messages in future versions of Windows.
- //
- // Arguments:
- // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
- // This structure is [optionally] allocated during the DRV_OPEN message
- // which is handled by the acmdDriverOpen function.
- //
- // HWND hwnd: Handle to parent window to use when displaying the
- // configuration dialog box. An ACM driver is _required_ to display a
- // modal dialog box using this hwnd argument as the parent. This
- // argument may be (HWND)-1 which tells the driver that it is only
- // being queried for configuration support.
- //
- // LPDRVCONFIGINFO pdci: Pointer to optional DRVCONFIGINFO structure.
- // If this argument is NULL, then the ACM driver should invent its own
- // storage location.
- //
- // Return (LRESULT):
- // If the driver is being 'queried' for configuration support (that is,
- // hwnd == (HWND)-1), then non-zero should be returned specifying
- // the driver does support a configuration dialog--or zero should be
- // returned specifying that no configuration dialog is supported.
- //
- // If the driver is being called to display the configuration dialog
- // (that is, hwnd != (HWND)-1), then one of the following values
- // should be returned:
- //
- // DRVCNF_CANCEL (0x0000): specifies that the dialog was displayed
- // and canceled by the user. this value should also be returned if
- // no configuration information was modified.
- //
- // DRVCNF_OK (0x0001): specifies that the dialog was displayed and
- // some configuration information was changed. however, the driver
- // does not require Windows to be restarted--the changes have already
- // been applied.
- //
- // DRVCNF_RESTART (0x0002): specifies that the dialog was displayed
- // and some configuration information was changed that requires
- // Windows to be restarted before the changes take affect. the driver
- // should remain configured with current values until the driver
- // has been 'rebooted'.
- //
- //--------------------------------------------------------------------------;
-
- LRESULT FNLOCAL acmdDriverConfigure
- (
- PDRIVERINSTANCE pdi,
- HWND hwnd,
- LPDRVCONFIGINFO pdci
- )
- {
- //
- // first check to see if we are only being queried for configuration
- // support. if hwnd == (HWND)-1 then we are being queried and should
- // return zero for 'not supported' and non-zero for 'supported'.
- //
- if ((HWND)-1 == hwnd)
- {
- //
- // this ACM driver does not support a configuration dialog box, so
- // return zero...
- //
- return (0L);
- }
-
-
- //
- // we are being asked to bring up our configuration dialog. if this
- // driver supports a configuration dialog box, then after the dialog
- // is dismissed we must return one of the following values:
- //
- // DRVCNF_CANCEL (0x0000): specifies that the dialog was displayed
- // and canceled by the user. this value should also be returned if
- // no configuration information was modified.
- //
- // DRVCNF_OK (0x0001): specifies that the dialog was displayed and
- // some configuration information was changed. however, the driver
- // does not require Windows to be restarted--the changes have already
- // been applied.
- //
- // DRVCNF_RESTART (0x0002): specifies that the dialog was displayed
- // and some configuration information was changed that requires
- // Windows to be restarted before the changes take affect. the driver
- // should remain configured with current values until the driver
- // has been 'rebooted'.
- //
- //
- if (NULL == pdci)
- {
- //
- // !!!
- //
- return (DRVCNF_CANCEL);
- }
-
- #if 0
- int n;
-
- pdi->pdci = pdci;
-
- n = DialogBoxParam(ghinst,
- DLG_CONFIGURATION,
- hwnd,
- msfilterDlgProcConfigure,
- (LPARAM)(UINT)pdi);
-
- pdi->pdci = NULL;
-
- return ((LRESULT)n);
- #else
- return (DRVCNF_CANCEL);
- #endif
- } // acmdDriverConfigure()
-
-
- //--------------------------------------------------------------------------;
- //
- // LRESULT acmdDriverDetails
- //
- // Description:
- // This function handles the ACMDM_DRIVER_DETAILS message. The ACM
- // driver is responsible for filling in the ACMDRIVERDETAILS structure
- // with various information.
- //
- // NOTE! It is *VERY* important that you fill in your ACMDRIVERDETAILS
- // structure correctly. The ACM and applications must be able to
- // rely on this information.
- //
- // WARNING! The _reserved_ bits of any fields of the ACMDRIVERDETAILS
- // structure are _exactly that_: RESERVED. Do NOT use any extra
- // flag bits, etc. for custom information. The proper way to add
- // custom capabilities to your ACM driver is this:
- //
- // o define a new message in the ACMDM_USER range.
- //
- // o an application that wishes to use one of these extra features
- // should then:
- //
- // o open the driver with acmDriverOpen.
- //
- // o check for the proper wMid and wPid using acmDriverDetails.
- //
- // o send the 'user defined' message with acmDriverMessage
- // to retrieve additional information, etc.
- //
- // o close the driver with acmDriverClose.
- //
- // Arguments:
- // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
- // This structure is [optionally] allocated during the DRV_OPEN message
- // which is handled by the acmdDriverOpen function.
- //
- // LPACMDRIVERDETAILS padd: Pointer to ACMDRIVERDETAILS structure to
- // fill in for the caller. This structure may be larger or smaller than
- // the current definition of ACMDRIVERDETAILS--cbStruct specifies the
- // valid size.
- //
- // Return (LRESULT):
- // The return value is zero (MMSYSERR_NOERROR) for success. Non-zero
- // signifies that the driver details could not be retrieved.
- //
- // NOTE THAT THIS FUNCTION SHOULD NEVER FAIL! There are two possible
- // error conditions:
- //
- // o if padd is NULL or an invalid pointer.
- //
- // o if cbStruct is less than four; in this case, there is not enough
- // room to return the number of bytes filled in.
- //
- // Because these two error conditions are easily defined, the ACM
- // will catch these errors. The driver does NOT need to check for these
- // conditions.
- //
- //--------------------------------------------------------------------------;
-
- LRESULT FNLOCAL acmdDriverDetails
- (
- PDRIVERINSTANCE pdi,
- LPACMDRIVERDETAILS padd
- )
- {
- ACMDRIVERDETAILS add;
- DWORD cbStruct;
-
- //
- // it is easiest to fill in a temporary structure with valid info
- // and then copy the requested number of bytes to the destination
- // buffer.
- //
- cbStruct = min(padd->cbStruct, sizeof(ACMDRIVERDETAILS));
- add.cbStruct = cbStruct;
-
-
- //
- // for the current implementation of an ACM driver, the fccType and
- // fccComp members *MUST* always be ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC
- // ('audc') and ACMDRIVERDETAILS_FCCCOMP_UNDEFINED (0) respectively.
- //
- add.fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
- add.fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
-
-
- //
- // the manufacturer id (wMid) and product id (wPid) must be filled
- // in with your company's _registered_ identifier's. for more
- // information on these identifier's and how to get them registered
- // contact Microsoft and get the Multimedia Developer Registration Kit:
- //
- // Microsoft Corporation
- // Multimedia Technology Group
- // One Microsoft Way
- // Redmond, WA 98052-6399
- //
- // Developer Services Phone: (800) 227-4679 x11771
- //
- // note that during the development phase or your ACM driver, you may
- // use the reserved value of '0' for both wMid and wPid. however it
- // is not acceptable to ship a driver with these values.
- //
- add.wMid = MM_MICROSOFT;
- add.wPid = MM_MSFT_ACM_MSFILTER;
-
-
- //
- // the vdwACM and vdwDriver members contain version information for
- // the driver.
- //
- // vdwACM: must contain the version of the *ACM* that the driver was
- // _designed_ for. this is the _minimum_ version number of the ACM
- // that the driver will work with. this value must be >= V2.00.000.
- //
- // vdwDriver: the version of this ACM driver.
- //
- // ACM driver versions are 32 bit numbers broken into three parts as
- // follows (note these parts are displayed as decimal values):
- //
- // bits 24 - 31: 8 bit _major_ version number
- // bits 16 - 23: 8 bit _minor_ version number
- // bits 0 - 15: 16 bit build number
- //
- add.vdwACM = VERSION_MSACM;
- add.vdwDriver = VERSION_ACM_DRIVER;
-
-
- //
- // the following flags are used to specify the type of conversion(s)
- // that the ACM driver supports. note that a driver may support one or
- // more of these flags in any combination.
- //
- // ACMDRIVERDETAILS_SUPPORTF_CODEC: this flag is set if the driver
- // supports conversions from one format tag to another format tag. for
- // example, if a converter compresses or decompresses WAVE_FORMAT_PCM
- // and WAVE_FORMAT_IMA_ADPCM, then this bit should be set. this is
- // true even if the data is not actually changed in size--for example
- // a conversion from u-Law to A-Law will still set this bit because
- // the format tags differ.
- //
- // ACMDRIVERDETAILS_SUPPORTF_CONVERTER: this flags is set if the
- // driver supports conversions on the same format tag. as an example,
- // the PCM converter that is built into the ACM sets this bit (and only
- // this bit) because it converts only between PCM formats (bits, sample
- // rate).
- //
- // ACMDRIVERDETAILS_SUPPORTF_FILTER: this flag is set if the driver
- // supports transformations on a single format tag but does change
- // the base characteristics of the format (bit depth, sample rate, etc
- // will remain the same). for example, a driver that changed the
- // 'volume' of PCM data or applied a low pass filter would set this bit.
- //
- add.fdwSupport = ACMDRIVERDETAILS_SUPPORTF_FILTER;
-
-
- //
- // the number of individual format tags this ACM driver supports. for
- // example, if a driver uses the WAVE_FORMAT_IMA_ADPCM and
- // WAVE_FORMAT_PCM format tags, then this value would be two. if the
- // driver only supports filtering on WAVE_FORMAT_PCM, then this value
- // would be one. if this driver supported WAVE_FORMAT_ALAW,
- // WAVE_FORMAT_MULAW and WAVE_FORMAT_PCM, then this value would be
- // three. etc, etc.
- //
- add.cFormatTags = ACM_DRIVER_MAX_FORMAT_TAGS;
-
- //
- // the number of individual filter tags this ACM driver supports. if
- // a driver supports no filters (ACMDRIVERDETAILS_SUPPORTF_FILTER is
- // NOT set in the fdwSupport member), then this value must be zero.
- //
- add.cFilterTags = ACM_DRIVER_MAX_FILTER_TAGS;
-
-
- //
- // the remaining members in the ACMDRIVERDETAILS structure are sometimes
- // not needed. because of this we make a quick check to see if we
- // should go through the effort of filling in these members.
- //
- if (FIELD_OFFSET(ACMDRIVERDETAILS, hicon) < cbStruct)
- {
- //
- // fill in the hicon member will a handle to a custom icon for
- // the ACM driver. this allows the driver to be represented by
- // an application graphically (usually this will be a company
- // logo or something). if a driver does not wish to have a custom
- // icon displayed, then simply set this member to NULL and a
- // generic icon will be displayed instead.
- //
- #ifdef DEBUG
- add.hicon = LoadIcon(ghinst, ICON_ACM_DRIVER); // NULL
- #else
- add.hicon = NULL;
- #endif
-
- //
- // the short name and long name are used to represent the driver
- // in a unique description. the short name is intended for small
- // display areas (for example, in a menu or combo box). the long
- // name is intended for more descriptive displays (for example,
- // in an 'about box').
- //
- // NOTE! an ACM driver should never place formatting characters
- // of any sort in these strings (for example CR/LF's, etc). it
- // is up to the application to format the text.
- //
- LoadString(ghinst, IDS_ACM_DRIVER_SHORTNAME, add.szShortName, SIZEOF(add.szShortName));
- LoadString(ghinst, IDS_ACM_DRIVER_LONGNAME, add.szLongName, SIZEOF(add.szLongName));
-
- //
- // the last three members are intended for 'about box' information.
- // these members are optional and may be zero length strings if
- // the driver wishes.
- //
- // NOTE! an ACM driver should never place formatting characters
- // of any sort in these strings (for example CR/LF's, etc). it
- // is up to the application to format the text.
- //
- if (FIELD_OFFSET(ACMDRIVERDETAILS, szCopyright) < cbStruct)
- {
- LoadString(ghinst, IDS_ACM_DRIVER_COPYRIGHT, add.szCopyright, SIZEOF(add.szCopyright));
- LoadString(ghinst, IDS_ACM_DRIVER_LICENSING, add.szLicensing, SIZEOF(add.szLicensing));
- LoadString(ghinst, IDS_ACM_DRIVER_FEATURES, add.szFeatures, SIZEOF(add.szFeatures));
- }
- }
-
-
- //
- // now copy the correct number of bytes to the caller's buffer
- //
- _fmemcpy(padd, &add, (UINT)add.cbStruct);
-
-
- //
- // success!
- //
- return (MMSYSERR_NOERROR);
- } // acmdDriverDetails()
-
-
- //--------------------------------------------------------------------------;
- //
- // LRESULT acmdDriverAbout
- //
- // Description:
- // This function is called to handle the ACMDM_DRIVER_ABOUT message.
- // An ACM driver has the option of displaying its own 'about box' or
- // letting the ACM (or calling application) display one for it. This
- // message is normally sent by the Control Panel's Sound Mapper
- // option.
- //
- // It is recommended that an ACM driver allow a default about box
- // be displayed for it--there should be no reason to bloat the size
- // of a driver to simply display copyright, etc information when that
- // information is contained in the ACMDRIVERDETAILS structure.
- //
- // Arguments:
- // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
- // This structure is [optionally] allocated during the DRV_OPEN message
- // which is handled by the acmdDriverOpen function.
- //
- // HWND hwnd: Handle to parent window to use when displaying the
- // configuration dialog box. An ACM driver is _required_ to display a
- // modal dialog box using this hwnd argument as the parent. This
- // argument may be (HWND)-1 which tells the driver that it is only
- // being queried for about box support.
- //
- // Return (LRESULT):
- // The return value is MMSYSERR_NOTSUPPORTED if the ACM driver does
- // not support a custom dialog box. In this case, the ACM or calling
- // application will display a generic about box using the information
- // contained in the ACMDRIVERDETAILS structure returned by the
- // ACMDM_DRIVER_DETAILS message.
- //
- // If the driver chooses to display its own dialog box, then after
- // the dialog is dismissed by the user, MMSYSERR_NOERROR should be
- // returned.
- //
- // If the hwnd argument is equal to (HWND)-1, then no dialog should
- // be displayed (the driver is only being queried for support). The
- // driver must still return MMSYSERR_NOERROR (supported) or
- // MMSYSERR_NOTSUPPORTED (no custom about box supported).
- //
- //--------------------------------------------------------------------------;
-
- LRESULT FNLOCAL acmdDriverAbout
- (
- PDRIVERINSTANCE pdi,
- HWND hwnd
- )
- {
- //
- // first check to see if we are only being queried for custom about
- // box support. if hwnd == (HWND)-1 then we are being queried and
- // should return MMSYSERR_NOTSUPPORTED for 'not supported' and
- // MMSYSERR_NOERROR for 'supported'.
- //
- if ((HWND)-1 == hwnd)
- {
- //
- // this ACM driver does NOT support a custom about box, so
- // return MMSYSERR_NOTSUPPORTED...
- //
- return (MMSYSERR_NOTSUPPORTED);
- }
-
-
- //
- // this driver does not support a custom dialog, so tell the ACM or
- // calling application to display one for us. note that this is the
- // _recommended_ method for consistency and simplicity of ACM drivers.
- // why write code when you don't have to?
- //
- return (MMSYSERR_NOTSUPPORTED);
- } // acmdDriverAbout()
-
-
- //==========================================================================;
- //
- //
- //
- //
- //==========================================================================;
-
- //--------------------------------------------------------------------------;
- //
- // LRESULT acmdFormatTagDetails
- //
- // Description:
- // This function handles the ACMDM_FORMATTAG_DETAILS message. This
- // message is normally sent in response to an acmFormatTagDetails or
- // acmFormatTagEnum function call. The purpose of this function is
- // to get details about a specific format tag supported by this ACM
- // driver.
- //
- // Arguments:
- // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
- // This structure is [optionally] allocated during the DRV_OPEN message
- // which is handled by the acmdDriverOpen function.
- //
- // LPACMFORMATTAGDETAILS padft: Pointer to an ACMFORMATTAGDETAILS
- // structure that describes what format tag to retrieve details for.
- //
- // DWORD fdwDetails: Flags defining what format tag to retrieve the
- // details for.
- //
- // Return (LRESULT):
- // The return value is zero (MMSYSERR_NOERROR) if this function
- // succeeds with no errors. The return value is a non-zero error code
- // if the function fails.
- //
- // The driver should return MMSYSERR_NOTSUPPORTED if the query type
- // specified in fdwDetails is not supported. An ACM driver must
- // support at least the following query types:
- //
- // ACM_FORMATTAGDETAILSF_INDEX: Indicates that a format tag index
- // was given in the dwFormatTagIndex member of the ACMFORMATTAGDETAILS
- // structure. The format tag and details must be returned in the
- // structure specified by padft. The index ranges from zero to one less
- // than the cFormatTags member returned in the ACMDRIVERDETAILS
- // structure for this driver.
- //
- // ACM_FORMATTAGDETAILSF_FORMATTAG: Indicates that a format tag
- // was given in the dwFormatTag member of the ACMFORMATTAGDETAILS
- // structure. The format tag details must be returned in the structure
- // specified by padft.
- //
- // ACM_FORMATTAGDETAILSF_LARGESTSIZE: Indicates that the details
- // on the format tag with the largest format size in bytes must be
- // returned. The dwFormatTag member will either be WAVE_FORMAT_UNKNOWN
- // or the format tag to find the largest size for.
- //
- // If the details for the specified format tag cannot be retrieved
- // from this driver, then ACMERR_NOTPOSSIBLE should be returned.
- //
- //--------------------------------------------------------------------------;
-
- LRESULT FNLOCAL acmdFormatTagDetails
- (
- PDRIVERINSTANCE pdi,
- LPACMFORMATTAGDETAILS padft,
- DWORD fdwDetails
- )
- {
- UINT uFormatTag;
-
- //
- //
- //
- //
- //
- switch (ACM_FORMATTAGDETAILSF_QUERYMASK & fdwDetails)
- {
- case ACM_FORMATTAGDETAILSF_INDEX:
- //
- // if the index is too large, then they are asking for a
- // non-existant format. return error.
- //
- if (ACM_DRIVER_MAX_FORMAT_TAGS <= padft->dwFormatTagIndex)
- return (ACMERR_NOTPOSSIBLE);
-
- uFormatTag = gauFormatTagIndexToTag[(UINT)padft->dwFormatTagIndex];
- break;
-
-
- case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
- switch (padft->dwFormatTag)
- {
- case WAVE_FORMAT_UNKNOWN:
- case WAVE_FORMAT_PCM:
- uFormatTag = WAVE_FORMAT_PCM;
- break;
-
- default:
- return (ACMERR_NOTPOSSIBLE);
- }
- break;
-
-
- case ACM_FORMATTAGDETAILSF_FORMATTAG:
- if (WAVE_FORMAT_PCM != padft->dwFormatTag)
- return (ACMERR_NOTPOSSIBLE);
-
- uFormatTag = WAVE_FORMAT_PCM;
- break;
-
-
- //
- // if this ACM driver does not understand a query type, then
- // return 'not supported'
- //
- default:
- return (MMSYSERR_NOTSUPPORTED);
- }
-
-
-
- //
- //
- //
- //
- switch (uFormatTag)
- {
- case WAVE_FORMAT_PCM:
- padft->dwFormatTagIndex = 0;
- padft->dwFormatTag = WAVE_FORMAT_PCM;
- padft->cbFormatSize = sizeof(PCMWAVEFORMAT);
- padft->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_FILTER;
- padft->cStandardFormats = ACM_DRIVER_MAX_STANDARD_FORMATS_PCM;
-
- //
- // the ACM is responsible for the PCM format tag name
- //
- padft->szFormatTag[0] = '\0';
- break;
-
- default:
- return (ACMERR_NOTPOSSIBLE);
- }
-
-
- //
- // return only the requested info
- //
- // the ACM will guarantee that the ACMFORMATTAGDETAILS structure
- // passed is at least large enough to hold the base information of
- // the details structure
- //
- padft->cbStruct = min(padft->cbStruct, sizeof(*padft));
-
-
- //
- //
- //
- return (MMSYSERR_NOERROR);
- } // acmdFormatTagDetails()
-
-
- //--------------------------------------------------------------------------;
- //
- // LRESULT acmdFormatDetails
- //
- // Description:
- // This function handles the ACMDM_FORMAT_DETAILS message. This
- // message is normally sent in response to an acmFormatDetails or
- // acmFormatEnum function call. The purpose of this function is
- // to get details about a specific format for a specified format tag
- // supported by this ACM driver.
- //
- // Note that an ACM driver can return a zero length string for the
- // format name if it wishes to have the ACM create a format string
- // for it. This is strongly recommended to simplify internationalizing
- // the driver--the ACM will automatically take care of that. The
- // following formula is used to format a string by the ACM:
- //
- // <nSamplesPerSec> kHz, <bit depth> bit, [Mono | Stereo | nChannels]
- //
- // <bit depth> = <nAvgBytesPerSec> * 8 / nSamplesPerSec / nChannels;
- //
- // Arguments:
- // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
- // This structure is [optionally] allocated during the DRV_OPEN message
- // which is handled by the acmdDriverOpen function.
- //
- // LPACMFORMATDETAILS padf: Pointer to an ACMFORMATDETAILS structure
- // that describes what format (for a specified format tag) to retrieve
- // details for.
- //
- // DWORD fdwDetails: Flags defining what format for a specified format
- // tag to retrieve the details for.
- //
- // Return (LRESULT):
- // The return value is zero (MMSYSERR_NOERROR) if this function
- // succeeds with no errors. The return value is a non-zero error code
- // if the function fails.
- //
- // The driver should return MMSYSERR_NOTSUPPORTED if the query type
- // specified in fdwDetails is not supported. An ACM driver must
- // support at least the following query types:
- //
- // ACM_FORMATDETAILSF_INDEX: Indicates that a format index for the
- // format tag was given in the dwFormatIndex member of the
- // ACMFORMATDETAILS structure. The format details must be returned in
- // the structure specified by padf. The index ranges from zero to one
- // less than the cStandardFormats member returned in the
- // ACMFORMATTAGDETAILS structure for a format tag.
- //
- // ACM_FORMATDETAILSF_FORMAT: Indicates that a WAVEFORMATEX structure
- // pointed to by pwfx of the ACMFORMATDETAILS structure was given and
- // the remaining details should be returned. The dwFormatTag member
- // of the ACMFORMATDETAILS will be initialized to the same format
- // tag as the pwfx member specifies. This query type may be used to
- // get a string description of an arbitrary format structure.
- //
- // If the details for the specified format cannot be retrieved
- // from this driver, then ACMERR_NOTPOSSIBLE should be returned.
- //
- //--------------------------------------------------------------------------;
-
- LRESULT FNLOCAL acmdFormatDetails
- (
- PDRIVERINSTANCE pdi,
- LPACMFORMATDETAILS padf,
- DWORD fdwDetails
- )
- {
- LPWAVEFORMATEX pwfx;
- UINT uFormatIndex;
- UINT u;
-
-
- //
- //
- //
- //
- //
- switch (ACM_FORMATDETAILSF_QUERYMASK & fdwDetails)
- {
- //
- // enumerate by index
- //
- // verify that the format tag is something we know about and
- // return the details on the 'standard format' supported by
- // this driver at the specified index...
- //
- case ACM_FORMATDETAILSF_INDEX:
- //
- // verify that the format tag is something we know about
- //
- if (WAVE_FORMAT_PCM != padf->dwFormatTag)
- return (ACMERR_NOTPOSSIBLE);
-
- if (ACM_DRIVER_MAX_STANDARD_FORMATS_PCM <= padf->dwFormatIndex)
- return (ACMERR_NOTPOSSIBLE);
-
- //
- // put some stuff in more accessible variables--note that we
- // bring variable sizes down to a reasonable size for 16 bit
- // code...
- //
- pwfx = padf->pwfx;
- uFormatIndex = (UINT)padf->dwFormatIndex;
-
- //
- // now fill in the format structure
- //
- pwfx->wFormatTag = WAVE_FORMAT_PCM;
-
- u = uFormatIndex / (ACM_DRIVER_MAX_BITSPERSAMPLE_PCM * ACM_DRIVER_MAX_CHANNELS);
- pwfx->nSamplesPerSec = gauFormatIndexToSampleRate[u];
-
- u = uFormatIndex % ACM_DRIVER_MAX_CHANNELS;
- pwfx->nChannels = u + 1;
-
- u = (uFormatIndex / ACM_DRIVER_MAX_CHANNELS) % ACM_DRIVER_MAX_CHANNELS;
- pwfx->wBitsPerSample = gauFormatIndexToBitsPerSample[u];
-
- pwfx->nBlockAlign = PCM_BLOCKALIGNMENT(pwfx);
- pwfx->nAvgBytesPerSec = PCM_AVGBYTESPERSEC(pwfx);
-
-
- //
- // note that the cbSize field is NOT valid for PCM formats
- //
- // pwfx->cbSize = 0;
- break;
-
-
- //
- // return details on specified format
- //
- // the caller normally uses this to verify that the format is
- // supported and to retrieve a string description...
- //
- case ACM_FORMATDETAILSF_FORMAT:
- if (!pcmIsValidFormat(padf->pwfx))
- return (ACMERR_NOTPOSSIBLE);
-
- break;
-
-
- default:
- //
- // don't know how to do the query type passed--return 'not
- // supported'.
- //
- return (MMSYSERR_NOTSUPPORTED);
- }
-
-
- //
- // return the size of the valid information we are returning
- //
- // the ACM will guarantee that the ACMFORMATDETAILS structure
- // passed is at least large enough to hold the base structure
- //
- // note that we let the ACM create the format string for us since
- // we require no special formatting (and don't want to deal with
- // internationalization issues, etc). simply set the string to
- // a zero length.
- //
- padf->cbStruct = min(padf->cbStruct, sizeof(*padf));
- padf->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_FILTER;
- padf->szFormat[0] = '\0';
-
-
- //
- //
- //
- return (MMSYSERR_NOERROR);
- } // acmdFormatDetails()
-
-
- //==========================================================================;
- //
- //
- //
- //
- //==========================================================================;
-
- //--------------------------------------------------------------------------;
- //
- // LRESULT acmdFilterTagDetails
- //
- // Description:
- //
- //
- // Arguments:
- // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
- // This structure is [optionally] allocated during the DRV_OPEN message
- // which is handled by the acmdDriverOpen function.
- //
- // LPACMFILTERTAGDETAILS padft:
- //
- // DWORD fdwDetails:
- //
- // Return (LRESULT):
- //
- //
- //--------------------------------------------------------------------------;
-
- LRESULT FNLOCAL acmdFilterTagDetails
- (
- PDRIVERINSTANCE pdi,
- LPACMFILTERTAGDETAILS padft,
- DWORD fdwDetails
- )
- {
- UINT uIds;
- UINT uFilterTag;
-
- //
- //
- //
- //
- //
- switch (ACM_FILTERTAGDETAILSF_QUERYMASK & fdwDetails)
- {
- case ACM_FILTERTAGDETAILSF_INDEX:
- //
- // if the index is too large, then they are asking for a
- // non-existant filter. return error.
- //
- if (ACM_DRIVER_MAX_FILTER_TAGS <= padft->dwFilterTagIndex)
- return (ACMERR_NOTPOSSIBLE);
-
- uFilterTag = (UINT)gadwFilterTagIndexToTag[(UINT)padft->dwFilterTagIndex];
- break;
-
-
- case ACM_FILTERTAGDETAILSF_LARGESTSIZE:
- switch (padft->dwFilterTag)
- {
- case WAVE_FILTER_UNKNOWN:
- case WAVE_FILTER_ECHO:
- uFilterTag = WAVE_FILTER_ECHO;
- break;
-
- case WAVE_FILTER_VOLUME:
- uFilterTag = WAVE_FILTER_VOLUME;
- break;
-
- default:
- return (ACMERR_NOTPOSSIBLE);
- }
- break;
-
-
- case ACM_FILTERTAGDETAILSF_FILTERTAG:
- switch (padft->dwFilterTag)
- {
- case WAVE_FILTER_VOLUME:
- uFilterTag = WAVE_FILTER_VOLUME;
- break;
-
- case WAVE_FILTER_ECHO:
- uFilterTag = WAVE_FILTER_ECHO;
- break;
-
- default:
- return (ACMERR_NOTPOSSIBLE);
- }
- break;
-
-
- //
- // if this driver does not understand a query type, then
- // return 'not supported'
- //
- default:
- return (MMSYSERR_NOTSUPPORTED);
- }
-
-
-
- //
- //
- //
- //
- switch (uFilterTag)
- {
- case WAVE_FILTER_VOLUME:
- padft->dwFilterTagIndex = 0;
- padft->dwFilterTag = WAVE_FILTER_VOLUME;
- padft->cbFilterSize = sizeof(VOLUMEWAVEFILTER);
- padft->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_FILTER;
- padft->cStandardFilters = ACM_DRIVER_MAX_VOLUME_FILTERS;
-
- uIds = IDS_ACM_DRIVER_TAG_NAME_VOLUME;
- break;
-
- case WAVE_FILTER_ECHO:
- padft->dwFilterTagIndex = 1;
- padft->dwFilterTag = WAVE_FILTER_ECHO;
- padft->cbFilterSize = sizeof(ECHOWAVEFILTER);
- padft->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_FILTER;
- padft->cStandardFilters = ACM_DRIVER_MAX_ECHO_FILTERS;
-
- uIds = IDS_ACM_DRIVER_TAG_NAME_ECHO;
- break;
-
- default:
- return (ACMERR_NOTPOSSIBLE);
- }
-
-
- //
- // return only the requested info
- //
- // the ACM will guarantee that the ACMFILTERTAGDETAILS structure
- // passed is at least large enough to hold the base structure
- //
- padft->cbStruct = min(padft->cbStruct, sizeof(*padft));
-
- LoadString(ghinst, uIds, padft->szFilterTag, SIZEOF(padft->szFilterTag));
-
-
- //
- //
- //
- return (MMSYSERR_NOERROR);
- } // acmdFilterTagDetails()
-
-
- //--------------------------------------------------------------------------;
- //
- // UINT acmdFilterDetailsToString
- //
- // Description:
- //
- //
- // Arguments:
- // LPWAVEFILTER pwf:
- //
- // LPTSTR szFilter:
- //
- // Return (UINT):
- //
- //
- //--------------------------------------------------------------------------;
-
- UINT FNLOCAL acmdFilterDetailsToString
- (
- LPWAVEFILTER pwf,
- LPTSTR szFilter
- )
- {
- UINT u;
- TCHAR ach[ACMFILTERDETAILS_FILTER_CHARS];
- LPVOLUMEWAVEFILTER pwfVol;
- LPECHOWAVEFILTER pwfEcho;
-
-
- if( !szFilter ) {
- return 0L;
- }
-
- *szFilter = '\0';
- if (volumeIsValidFilter(pwf))
- {
- pwfVol = (LPVOLUMEWAVEFILTER)pwf;
- LoadString(ghinst, IDS_ACM_DRIVER_FORMAT_VOLUME, ach, SIZEOF(ach));
- u = wsprintf( szFilter, ach,
- (WORD)(((pwfVol->dwVolume * 100) / 0x10000)) );
- return( u );
- }
- else if (echoIsValidFilter(pwf))
- {
- pwfEcho = (LPECHOWAVEFILTER)pwf;
- LoadString(ghinst, IDS_ACM_DRIVER_FORMAT_ECHO, ach, SIZEOF(ach));
- u = wsprintf( szFilter, ach,
- (WORD)(((pwfEcho->dwVolume * 100) / 0x10000)),
- (WORD)pwfEcho->dwDelay );
- return( u );
- }
- return ( 0 );
- } // acmdFilterDetailsToString()
-
-
-
- //--------------------------------------------------------------------------;
- //
- // LRESULT acmdFilterDetails
- //
- // Description:
- //
- //
- // Arguments:
- // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
- // This structure is [optionally] allocated during the DRV_OPEN message
- // which is handled by the acmdDriverOpen function.
- //
- // LPACMFILTERDETAILS padf:
- //
- // DWORD fdwDetails:
- //
- // Return (LRESULT):
- //
- //
- //--------------------------------------------------------------------------;
-
- LRESULT FNLOCAL acmdFilterDetails
- (
- PDRIVERINSTANCE pdi,
- LPACMFILTERDETAILS padf,
- DWORD fdwDetails
- )
- {
- UINT uFilterIndex;
- LPWAVEFILTER pwf;
- LPVOLUMEWAVEFILTER pwfVolume;
- LPECHOWAVEFILTER pwfEcho;
- UINT u;
-
- pwf = padf->pwfltr;
-
- //
- //
- //
- //
- //
- switch (ACM_FILTERDETAILSF_QUERYMASK & fdwDetails)
- {
- case ACM_FILTERDETAILSF_INDEX:
- //
- // enumerate by index
- //
- // for this converter, this is more code than necessary... just
- // verify that the filter tag is something we know about
- //
- switch (padf->dwFilterTag)
- {
- case WAVE_FILTER_VOLUME:
- if (ACM_DRIVER_MAX_VOLUME_FILTERS <= padf->dwFilterIndex)
- return (ACMERR_NOTPOSSIBLE);
-
- pwfVolume = (LPVOLUMEWAVEFILTER)padf->pwfltr;
- pwf->cbStruct = sizeof(VOLUMEWAVEFILTER);
- pwf->dwFilterTag = WAVE_FILTER_VOLUME;
- pwf->fdwFilter = 0;
- pwfVolume->dwVolume = gdwFilterIndexToVolume[(UINT)padf->dwFilterIndex];
- break;
-
- case WAVE_FILTER_ECHO:
- if (ACM_DRIVER_MAX_ECHO_FILTERS <= padf->dwFilterIndex)
- return (ACMERR_NOTPOSSIBLE);
-
- pwfEcho = (LPECHOWAVEFILTER)padf->pwfltr;
- pwf->cbStruct = sizeof(ECHOWAVEFILTER);
- pwf->dwFilterTag = WAVE_FILTER_ECHO;
- pwf->fdwFilter = 0;
-
- uFilterIndex = (UINT)padf->dwFilterIndex;
-
- u = uFilterIndex / ACM_DRIVER_NUM_DELAY;
- pwfEcho->dwVolume = gdwFilterIndexToEchoVol[u];
-
- u = uFilterIndex % ACM_DRIVER_NUM_DELAY;
- pwfEcho->dwDelay = gdwFilterIndexToDelay[u];
- break;
-
- default:
- return (ACMERR_NOTPOSSIBLE);
- }
-
- case ACM_FILTERDETAILSF_FILTER:
- //
- // must want to verify that the filter passed in is supported
- // and return a string description...
- //
- switch (pwf->dwFilterTag)
- {
- case WAVE_FILTER_VOLUME:
- if (!volumeIsValidFilter(pwf))
- return (ACMERR_NOTPOSSIBLE);
-
- break;
-
- case WAVE_FILTER_ECHO:
- if (!echoIsValidFilter(pwf))
- return (ACMERR_NOTPOSSIBLE);
-
- break;
-
- default:
- return (ACMERR_NOTPOSSIBLE);
- }
- break;
-
-
- default:
- //
- // don't know how to do the query type passed--return 'not
- // supported'.
- //
- return (MMSYSERR_NOTSUPPORTED);
- }
-
-
- //
- // return only the requested info
- //
- // the ACM will guarantee that the ACMFILTERDETAILS structure
- // passed is at least large enough to hold everything in the base
- // filter details structure...
- //
- // get a nice friendly string for the filter we made
- //
- acmdFilterDetailsToString(pwf, padf->szFilter);
-
-
- //
- // if they asked for more info than we know how to return, then
- // set size of valid structure bytes to correct value.
- //
- padf->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_FILTER;
- padf->cbStruct = min(padf->cbStruct, sizeof(*padf));
-
- //
- //
- //
- return (MMSYSERR_NOERROR);
- } // acmdFilterDetails()
-
-
-
- //==========================================================================;
- //
- //
- //
- //
- //==========================================================================;
-
- //--------------------------------------------------------------------------;
- //
- // LRESULT acmdStreamOpen
- //
- // Description:
- // This function handles the ACMDM_STREAM_OPEN message. This message
- // is sent to initiate a new conversion stream. This is usually caused
- // by an application calling acmStreamOpen. If this function is
- // successful, then one or more ACMDM_STREAM_CONVERT messages will be
- // sent to convert individual buffers (user calls acmStreamConvert).
- //
- // Note that an ACM driver will not receive open requests for ASYNC
- // or FILTER operations unless the ACMDRIVERDETAILS_SUPPORTF_ASYNC
- // or ACMDRIVERDETAILS_SUPPORTF_FILTER flags are set in the
- // ACMDRIVERDETAILS structure. There is no need for the driver to
- // check for these requests unless it sets those support bits.
- //
- // If the ACM_STREAMOPENF_QUERY flag is set in the padsi->fdwOpen
- // member, then no resources should be allocated. Just verify that
- // the conversion request is possible by this driver and return the
- // appropriate error (either ACMERR_NOTPOSSIBLE or MMSYSERR_NOERROR).
- // The driver will NOT receive an ACMDM_STREAM_CLOSE for queries.
- //
- // If the ACM_STREAMOPENF_NONREALTIME bit is NOT set, then conversion
- // must be done in 'real-time'. This is a tough one to describe
- // exactly. If the driver may have trouble doing the conversion without
- // breaking up the audio, then a configuration dialog might be used
- // to allow the user to specify whether the real-time conversion
- // request should be succeeded. DO NOT SUCCEED THE CALL UNLESS YOU
- // ACTUALLY CAN DO REAL-TIME CONVERSIONS! There may be another driver
- // installed that can--so if you succeed the call you are hindering
- // the performance of the user's system! Don't be foolish.
- //
- // Arguments:
- // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
- // This structure is [optionally] allocated during the DRV_OPEN message
- // which is handled by the acmdDriverOpen function.
- //
- // LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the
- // conversion stream. This structure was allocated by the ACM and
- // filled with the most common instance data needed for conversions.
- // This structure will be passed back to all future stream messages
- // if the open succeeds. The information in this structure will never
- // change during the lifetime of the stream--so it is not necessary
- // to re-verify the information referenced by this structure.
- //
- // Return (LRESULT):
- // The return value is zero (MMSYSERR_NOERROR) if this function
- // succeeds with no errors. The return value is a non-zero error code
- // if the function fails.
- //
- // A driver should return ACMERR_NOTPOSSIBLE if the conversion cannot
- // be performed due to incompatible source and destination formats.
- //
- // A driver should return MMSYSERR_NOTSUPPORTED if the conversion
- // cannot be performed in real-time and the request does not specify
- // the ACM_STREAMOPENF_NONREALTIME flag.
- //
- //--------------------------------------------------------------------------;
-
- LRESULT FNLOCAL acmdStreamOpen
- (
- PDRIVERINSTANCE pdi,
- LPACMDRVSTREAMINSTANCE padsi
- )
- {
- PSTREAMINSTANCE psi;
- LPWAVEFORMATEX pwfxSrc;
- LPWAVEFORMATEX pwfxDst;
- LPWAVEFILTER pwfltr;
- BOOL fRealTime;
-
-
- //
- //
- //
- pwfxSrc = padsi->pwfxSrc;
- pwfxDst = padsi->pwfxDst;
- pwfltr = padsi->pwfltr;
-
- fRealTime = (0 == (padsi->fdwOpen & ACM_STREAMOPENF_NONREALTIME));
-
- if( fRealTime )
- {
- //
- // We only do non-realtime conversions.
- // Return failure if we are asked for realtime.
- //
- return (ACMERR_NOTPOSSIBLE);
- }
-
-
- //
- // the most important condition to check before doing anything else
- // is that this ACM driver can actually perform the conversion we are
- // being opened for. this check should fail as quickly as possible
- // if the conversion is not possible by this driver.
- //
- // it is VERY important to fail quickly so the ACM can attempt to
- // find a driver that is suitable for the conversion. also note that
- // the ACM may call this driver several times with slightly different
- // format specifications before giving up.
- //
- // this driver first verifies that the source and destination formats
- // are acceptable...
- //
- // NOTE! for a 'filter only' driver, you only need to check one
- // of the formats. the ACM will have already verified that the source
- // and destination formats are equal. so if one is acceptable to this
- // driver, they both are.
- //
- if (!pcmIsValidFormat(pwfxSrc))
- {
- //
- // either the source or destination format is illegal for this
- // driver--or the conversion between the formats can not be
- // performed by this driver.
- //
- return (ACMERR_NOTPOSSIBLE);
- }
-
-
- //
- // now verify the filter..
- //
- if (!volumeIsValidFilter(pwfltr) && !echoIsValidFilter(pwfltr))
- {
- return (ACMERR_NOTPOSSIBLE);
- }
-
-
-
- //
- // we have determined that the conversion requested is possible by
- // this driver. now check if we are just being queried for support.
- // if this is just a query, then do NOT allocate any instance data
- // or create tables, etc. just succeed the call.
- //
- if (0 != (ACM_STREAMOPENF_QUERY & padsi->fdwOpen))
- {
- return (MMSYSERR_NOERROR);
- }
-
-
- //
- // we have decided that this driver can handle the conversion stream.
- // so we want to do _AS MUCH WORK AS POSSIBLE_ right now to prepare
- // for converting data. any resource allocation, table building, etc
- // that can be dealt with at this time should be done.
- //
- // THIS IS VERY IMPORTANT! all ACMDM_STREAM_CONVERT messages need to
- // be handled as quickly as possible.
- //
- //
-
- //
- // we have decided that this driver can handle the conversion stream.
- // so we want to do _AS MUCH WORK AS POSSIBLE_ right now to prepare
- // for converting data. any resource allocation, table building, etc
- // that can be dealt with at this time should be done.
- //
- // THIS IS VERY IMPORTANT! all ACMDM_STREAM_CONVERT messages need to
- // be handled as quickly as possible.
- //
- // this driver allocates a small instance structure for each stream
- //
- //
- psi = (PSTREAMINSTANCE)LocalAlloc(LPTR, sizeof(*psi));
- if (NULL == psi)
- {
- return (MMSYSERR_NOMEM);
- }
-
-
- //
- // fill out our instance structure
- //
- // this driver stores a pointer to the conversion function that will
- // be used for each conversion on this stream. we also store a
- // copy of the _current_ configuration of the driver instance we
- // are opened on. this must not change during the life of the stream
- // instance.
- //
- // this is also very important! if the user is able to configure how
- // the driver performs conversions, the changes should only affect
- // future open streams. all current open streams should behave as
- // they were configured during the open.
- //
-
- //
- //
- //
- //
- if (WAVE_FILTER_VOLUME == pwfltr->dwFilterTag)
- {
- psi->fnConvert = msfilterVolume;
- psi->fdwConfig = pdi->fdwConfig;
- psi->hpbHistory = NULL;
- psi->dwPlace = 0L;
- psi->dwHistoryDone = 0L;
- }
- else
- {
- LPECHOWAVEFILTER pwfEcho;
- DWORD cb;
- LPBYTE pb;
-
- psi->fnConvert = msfilterEcho;
- psi->fdwConfig = pdi->fdwConfig;
- psi->hpbHistory = NULL;
- psi->dwPlace = 0L;
- psi->dwHistoryDone = 0L;
-
- pwfEcho = (LPECHOWAVEFILTER)pwfltr;
-
- //
- // compute size of delay buffer--add 4 because we're lame!
- //
- cb = (pwfxSrc->nSamplesPerSec * pwfEcho->dwDelay / 1000) *
- pwfxSrc->nBlockAlign;
- cb += 4;
-
- pb = (LPBYTE)GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE|GMEM_ZEROINIT, cb);
- if (NULL == pb)
- {
- //
- // free the stream instance structure and fail with no memory
- //
- LocalFree((HLOCAL)psi);
- return (MMSYSERR_NOMEM);
- }
-
- psi->hpbHistory = (BYTE _huge *)pb;
- }
-
-
- //
- // fill in our instance data--this will be passed back to all stream
- // messages in the ACMDRVSTREAMINSTANCE structure. it is entirely
- // up to the driver what gets stored (and maintained) in the
- // fdwDriver and dwDriver members.
- //
- padsi->fdwDriver = 0L;
- padsi->dwDriver = (DWORD)(UINT)psi;
-
- return (MMSYSERR_NOERROR);
- } // acmdStreamOpen()
-
-
- //--------------------------------------------------------------------------;
- //
- // LRESULT acmdStreamClose
- //
- // Description:
- // This function is called to handle the ACMDM_STREAM_CLOSE message.
- // This message is sent when a conversion stream is no longer being
- // used (the stream is being closed; usually by an application
- // calling acmStreamClose). The ACM driver should clean up any resources
- // that were allocated for the stream.
- //
- // Arguments:
- // LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the
- // conversion stream. This structure was allocated by the ACM and
- // filled with the most common instance data needed for conversions.
- // The information in this structure is exactly the same as it was
- // during the ACMDM_STREAM_OPEN message--so it is not necessary
- // to re-verify the information referenced by this structure.
- //
- // Return (LRESULT):
- // The return value is zero (MMSYSERR_NOERROR) if this function
- // succeeds with no errors. The return value is a non-zero error code
- // if the function fails.
- //
- // NOTE! It is _strongly_ recommended that a driver not fail to close
- // a conversion stream.
- //
- // An asyncronous conversion stream may fail with ACMERR_BUSY if there
- // are pending buffers. An application may call acmStreamReset to
- // force all pending buffers to be posted.
- //
- //--------------------------------------------------------------------------;
-
- LRESULT FNLOCAL acmdStreamClose
- (
- LPACMDRVSTREAMINSTANCE padsi
- )
- {
- PSTREAMINSTANCE psi;
-
- //
- // the driver should clean up all privately allocated resources that
- // were created for maintaining the stream instance. if no resources
- // were allocated, then simply succeed.
- //
- // in the case of this driver, we need to free the stream instance
- // structure that we allocated during acmdStreamOpen.
- //
- psi = (PSTREAMINSTANCE)(UINT)padsi->dwDriver;
- if (NULL != psi)
- {
- //
- // free up the delay buffer if one was allocated (will be for
- // the echo filter
- //
- if (NULL != psi->hpbHistory)
- {
- GlobalFreePtr(psi->hpbHistory);
- }
-
- //
- // free the stream instance structure
- //
- LocalFree((HLOCAL)psi);
- }
-
- return (MMSYSERR_NOERROR);
- } // acmdStreamClose()
-
-
- //--------------------------------------------------------------------------;
- //
- // LRESULT acmdStreamSize
- //
- // Description:
- // This function handles the ACMDM_STREAM_SIZE message. The purpose
- // of this function is to provide the _largest size in bytes_ that
- // the source or destination buffer needs to be given the input and
- // output formats and the size in bytes of the source or destination
- // data buffer.
- //
- // In other words: how big does my destination buffer need to be to
- // hold the converted data? (ACM_STREAMSIZEF_SOURCE)
- //
- // Or: how big can my source buffer be given the destination buffer?
- // (ACM_STREAMSIZEF_DESTINATION)
- //
- // Arguments:
- // LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the
- // conversion stream. This structure was allocated by the ACM and
- // filled with the most common instance data needed for conversions.
- // The information in this structure is exactly the same as it was
- // during the ACMDM_STREAM_OPEN message--so it is not necessary
- // to re-verify the information referenced by this structure.
- //
- // LPACMDRVSTREAMSIZE padss: Specifies a pointer to the ACMDRVSTREAMSIZE
- // structure that defines the conversion stream size query attributes.
- //
- // Return (LRESULT):
- // The return value is zero (MMSYSERR_NOERROR) if this function
- // succeeds with no errors. The return value is a non-zero error code
- // if the function fails.
- //
- // An ACM driver should return MMSYSERR_NOTSUPPORTED if a query type
- // is requested that the driver does not understand. Note that a driver
- // must support both the ACM_STREAMSIZEF_DESTINATION and
- // ACM_STREAMSIZEF_SOURCE queries.
- //
- // If the conversion would be 'out of range' given the input arguments,
- // then ACMERR_NOTPOSSIBLE should be returned.
- //
- //--------------------------------------------------------------------------;
-
- LRESULT FNLOCAL acmdStreamSize
- (
- LPACMDRVSTREAMINSTANCE padsi,
- LPACMDRVSTREAMSIZE padss
- )
- {
- LPWAVEFORMATEX pwfxSrc;
- LPWAVEFORMATEX pwfxDst;
- LPWAVEFILTER pwfltr;
- DWORD dw;
-
-
- pwfxSrc = padsi->pwfxSrc;
- pwfxDst = padsi->pwfxDst;
- pwfltr = padsi->pwfltr;
-
-
- //
- //
- //
- switch (ACM_STREAMSIZEF_QUERYMASK & padss->fdwSize)
- {
- case ACM_STREAMSIZEF_SOURCE:
- dw = padss->cbSrcLength;
-
- if( pwfltr->dwFilterTag == WAVE_FILTER_VOLUME )
- {
- //
- // Source and dest sizes are the same for volume.
- //
- // block align the destination
- //
- dw = PCM_BYTESTOSAMPLES(pwfxSrc, padss->cbSrcLength);
- dw = PCM_SAMPLESTOBYTES(pwfxSrc, dw);
- }
- else if( pwfltr->dwFilterTag == WAVE_FILTER_ECHO )
- {
- dw = PCM_BYTESTOSAMPLES(pwfxSrc, padss->cbSrcLength);
- dw = PCM_SAMPLESTOBYTES(pwfxSrc, dw);
- }
-
- if (0 == dw)
- {
- return (ACMERR_NOTPOSSIBLE);
- }
-
- padss->cbDstLength = dw;
- return (MMSYSERR_NOERROR);
-
-
- case ACM_STREAMSIZEF_DESTINATION:
- dw = padss->cbDstLength;
-
- if( pwfltr->dwFilterTag == WAVE_FILTER_VOLUME )
- {
- //
- // Source and dest sizes are the same for volume.
- //
- // block align the destination
- //
- dw = PCM_BYTESTOSAMPLES(pwfxDst, padss->cbDstLength);
- dw = PCM_SAMPLESTOBYTES(pwfxDst, dw);
- }
- else if( pwfltr->dwFilterTag == WAVE_FILTER_ECHO )
- {
- dw = PCM_BYTESTOSAMPLES(pwfxDst, padss->cbDstLength);
- dw = PCM_SAMPLESTOBYTES(pwfxDst, dw);
- }
-
- if (0 == dw)
- {
- return (ACMERR_NOTPOSSIBLE);
- }
-
- padss->cbSrcLength = dw;
- return (MMSYSERR_NOERROR);
- }
-
- //
- //
- //
- return (MMSYSERR_NOTSUPPORTED);
- } // acmdStreamSize()
-
-
- //==========================================================================;
- //
- //
- //
- //
- //==========================================================================;
-
- //--------------------------------------------------------------------------;
- //
- // LRESULT DriverProc
- //
- // Description:
- //
- //
- // Arguments:
- // DWORD dwId: For most messages, dwId is the DWORD value that
- // the driver returns in response to a DRV_OPEN message. Each time
- // the driver is opened, through the OpenDriver API, the driver
- // receives a DRV_OPEN message and can return an arbitrary, non-zero
- // value. The installable driver interface saves this value and returns
- // a unique driver handle to the application. Whenever the application
- // sends a message to the driver using the driver handle, the interface
- // routes the message to this entry point and passes the corresponding
- // dwId. This mechanism allows the driver to use the same or different
- // identifiers for multiple opens but ensures that driver handles are
- // unique at the application interface layer.
- //
- // The following messages are not related to a particular open instance
- // of the driver. For these messages, the dwId will always be zero.
- //
- // DRV_LOAD, DRV_FREE, DRV_ENABLE, DRV_DISABLE, DRV_OPEN
- //
- // HDRVR hdrvr: This is the handle returned to the application
- // by the driver interface.
- //
- // UINT uMsg: The requested action to be performed. Message
- // values below DRV_RESERVED are used for globally defined messages.
- // Message values from DRV_RESERVED to DRV_USER are used for defined
- // driver protocols. Messages above DRV_USER are used for driver
- // specific messages.
- //
- // LPARAM lParam1: Data for this message. Defined separately for
- // each message.
- //
- // LPARAM lParam2: Data for this message. Defined separately for
- // each message.
- //
- // Return (LRESULT):
- // Defined separately for each message.
- //
- //--------------------------------------------------------------------------;
-
- EXTERN_C LRESULT FNEXPORT DriverProc
- (
- DWORD dwId,
- HDRVR hdrvr,
- UINT uMsg,
- LPARAM lParam1,
- LPARAM lParam2
- )
- {
- LRESULT lr;
- PDRIVERINSTANCE pdi;
-
- //
- // make pdi either NULL or a valid instance pointer. note that dwId
- // is 0 for several of the DRV_* messages (ie DRV_LOAD, DRV_OPEN...)
- // see acmdDriverOpen for information on what dwId is for other
- // messages (instance data).
- //
- pdi = (PDRIVERINSTANCE)(UINT)dwId;
-
- switch (uMsg)
- {
- //
- // lParam1: Unused.
- //
- // lParam2: Unused.
- //
- case DRV_LOAD:
- case DRV_FREE:
- return (1L);
-
-
- //
- // lParam1: Not used. Ignore this argument.
- //
- // lParam2: Pointer to ACMDRVOPENDESC (or NULL).
- //
- case DRV_OPEN:
- lr = acmdDriverOpen(hdrvr, (LPACMDRVOPENDESC)lParam2);
- return (lr);
-
- //
- // lParam1: Unused.
- //
- // lParam2: Unused.
- //
- case DRV_CLOSE:
- lr = acmdDriverClose(pdi);
- return (lr);
-
- //
- // lParam1: Unused.
- //
- // lParam2: Unused.
- //
- case DRV_INSTALL:
- return ((LRESULT)DRVCNF_RESTART);
-
- //
- // lParam1: Unused.
- //
- // lParam2: Unused.
- //
- case DRV_REMOVE:
- return ((LRESULT)DRVCNF_RESTART);
-
-
-
- //
- // lParam1: Not used.
- //
- // lParam2: Not used.
- //
- case DRV_QUERYCONFIGURE:
- //
- // set up lParam1 and lParam2 to values that can be used by
- // acmdDriverConfigure to know that it is being 'queried'
- // for configuration support.
- //
- lParam1 = -1L;
- lParam2 = 0L;
-
- //--fall through--//
-
- //
- // lParam1: Handle to parent window for the configuration dialog
- // box.
- //
- // lParam2: Optional pointer to DRVCONFIGINFO structure.
- //
- case DRV_CONFIGURE:
- lr = acmdDriverConfigure(pdi, (HWND)lParam1, (LPDRVCONFIGINFO)lParam2);
- return (lr);
-
-
- //
- // lParam1: Pointer to ACMDRIVERDETAILS structure.
- //
- // lParam2: Size in bytes of ACMDRIVERDETAILS stucture passed.
- //
- case ACMDM_DRIVER_DETAILS:
- lr = acmdDriverDetails(pdi, (LPACMDRIVERDETAILS)lParam1);
- return (lr);
-
- //
- // lParam1: Handle to parent window to use if displaying your own
- // about box.
- //
- // lParam2: Not used.
- //
- case ACMDM_DRIVER_ABOUT:
- lr = acmdDriverAbout(pdi, (HWND)lParam1);
- return (lr);
-
- //--------------------------------------------------------------------------;
- //--------------------------------------------------------------------------;
-
- //
- // lParam1: Pointer to FORMATTAGDETAILS structure.
- //
- // lParam2: fdwDetails
- //
- case ACMDM_FORMATTAG_DETAILS:
- lr = acmdFormatTagDetails(pdi, (LPACMFORMATTAGDETAILS)lParam1, lParam2);
- return (lr);
-
-
- //
- // lParam1: Pointer to FORMATDETAILS structure.
- //
- // lParam2: fdwDetails
- //
- case ACMDM_FORMAT_DETAILS:
- lr = acmdFormatDetails(pdi, (LPACMFORMATDETAILS)lParam1, lParam2);
- return (lr);
-
- //--------------------------------------------------------------------------;
- //--------------------------------------------------------------------------;
-
- //
- // lParam1: FILTERTAGDETAILS
- //
- // lParam2: fdwDetails
- //
- case ACMDM_FILTERTAG_DETAILS:
- lr = acmdFilterTagDetails(pdi, (LPACMFILTERTAGDETAILS)lParam1, lParam2);
- return (lr);
-
- //
- // lParam1: Pointer to the details structure.
- //
- // lParam2: fdwDetails
- //
- case ACMDM_FILTER_DETAILS:
- lr = acmdFilterDetails(pdi, (LPACMFILTERDETAILS)lParam1, lParam2);
- return (lr);
-
- //--------------------------------------------------------------------------;
- //--------------------------------------------------------------------------;
-
- //
- // lParam1: Pointer to ACMDRVSTREAMINSTANCE structure.
- //
- // lParam2: Not used.
- //
- case ACMDM_STREAM_OPEN:
- lr = acmdStreamOpen(pdi, (LPACMDRVSTREAMINSTANCE)lParam1);
- return (lr);
-
- //
- // lParam1: Pointer to ACMDRVSTREAMINSTANCE structure.
- //
- // lParam2: Not Used.
- //
- case ACMDM_STREAM_CLOSE:
- lr = acmdStreamClose((LPACMDRVSTREAMINSTANCE)lParam1);
- return (lr);
-
- //
- // lParam1: Pointer to ACMDRVSTREAMINSTANCE structure.
- //
- // lParam2: Pointer to ACMDRVSTREAMSIZE structure.
- //
- case ACMDM_STREAM_SIZE:
- lr = acmdStreamSize((LPACMDRVSTREAMINSTANCE)lParam1, (LPACMDRVSTREAMSIZE)lParam2);
- return (lr);
-
- //
- // lParam1: Pointer to ACMDRVSTREAMINSTANCE structure.
- //
- // lParam2: Pointer to ACMDRVSTREAMHEADER structure.
- //
- case ACMDM_STREAM_CONVERT:
- {
- PSTREAMINSTANCE psi;
- LPACMDRVSTREAMINSTANCE padsi;
- LPACMDRVSTREAMHEADER padsh;
-
- //
- // our stream instance data is a pointer to the conversion
- // procedure needed to convert the pwfxSrc data to pwfxDst.
- // the correct procedure to use was decided in acmdStreamOpen
- //
- padsi = (LPACMDRVSTREAMINSTANCE)lParam1;
- padsh = (LPACMDRVSTREAMHEADER)lParam2;
-
- psi = (PSTREAMINSTANCE)(UINT)padsi->dwDriver;
-
- lr = psi->fnConvert(padsi, padsh);
- return (lr);
- }
- }
-
- //
- // if we are executing the following code, then this ACM driver does not
- // handle the message that was sent. there are two ranges of messages
- // we need to deal with:
- //
- // o ACM specific driver messages: if an ACM driver does not answer a
- // message sent in the ACM driver message range, then it must
- // return MMSYSERR_NOTSUPPORTED. this applies to the 'user'
- // range as well (for consistency).
- //
- // o other installable driver messages: if an ACM driver does not
- // answer a message that is NOT in the ACM driver message range,
- // then it must call DefDriverProc and return that result.
- // the exception to this is ACM driver procedures installed as
- // ACM_DRIVERADDF_FUNCTION through acmDriverAdd. in this case,
- // the driver procedure should conform to the ACMDRIVERPROC
- // prototype and also return zero instead of calling DefDriverProc.
- //
- if (uMsg >= ACMDM_USER)
- return (MMSYSERR_NOTSUPPORTED);
- else
- return (DefDriverProc(dwId, hdrvr, uMsg, lParam1, lParam2));
- } // DriverProc()
-